/**
 *\brief socket封装
 */
#ifndef _Socket_H
#define _Socket_H

#include <errno.h>
#include <unistd.h>
#include <cstdlib>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <netinet/in.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <sys/iocctl.h>
#include <net/if.h>
#include <pthread.h>
#include <zlib.h>  //compress
#include <fcntl.h> 
#include <iostream> 
#include <signal.h> 
#include <sys/epoll.h> 
#include <sys/poll.h> 
#include <vector>

#include "zMisc.h"
#include "zMutex.h"
#include "zNullCmd.h"
#include "Zebra.h"
#include "zTime.h"
#include "EncDec/EncDec.h"

const unsigned int trunkSize = 64*1024;
#define unzip_size(zip_size) ((zip_size) * 120 / 100 + 12)
const unsigned int PACKET_ZIP_BUFFER = unzip_size(trunkSize - 1) + sizeof(unsigned int) + 8; /**压缩需要的缓冲*/

#define CHECK_CURR_PTR(size) if(((unsigned int)-1 - _currPtr) <= (size)) \
				logger("缓冲区异常");

template <typename BufferType>
struct ByteBuffer
{
	public:
		ByteBuffer();

		inline void put(const unsigned char *buf,const unsigned int size)
		{
			wr_reserve(size);

			bcopy(buf,&_buffer[_currPtr],size);
	
			CHECK_CURR_PTR(size);
			_currPtr += size;
		}

		/*
		 *\brief 当前可写buffer的地址
		 */
		inline unsigned char *wr_buf()
		{
			return &_buffer[_currPtr];
		}
		/*
		 *\brief 缓存中有效数据的开始地址
		 */
		inline unsigned char *rd_buf()
		{
			return &_buffer[_offPtr];
		}
		inline unsigned int wr_size() const
		{
			return curPtr-offPtr;
		}

		/*
		 *\biref buffer has effective data
		 */
		inline bool rd_ready() const
		{
			if(_maxSize < _currPtr)	
			{
				logger("buffer error");
			}
			return _currPtr > _offPtr;
		}
		inline unsigned int rd_size() const
		{
			if(_maxSize < _currPtr)	
			{
				logger("buffer error");
			}
			return _currPtr - _offPtr;
		}

		void rd_flap(unsigned int size)
		{
			_offPtr += size;
			if(_currPtr > _offPtr)//curPtr-offPtr<offPtr
			{
				unsigned int tmp = _currPtr - _offPtr;
				if(_offPtr >= tm)
				{
					memmove(&_buffer[0],&_buffer[curPtr],tmp);	
					_offPtr = 0;
					_currPtr = tmp;
				}
			}
			else
			{
				_offPtr = 0;
				_currPtr = 0;
			}
		}

		inline unsigned int wr_size() const
		{
			return _maxSize - _currPtr;
		}
		inline void wr_flip(const unsigned int size)
		{
			CHECK_CURR_PTR(size);
			_currPtr += size;
		}

		inline void reset()
		{
			_offPtr = 0;
			_currPtr = 0;
		}

		inline unsigned int maxSize() const
		{
			return _maxSize;
		}
		inline unsigned int offPtr() const
		{
			return _offPtr;
		}
		inline unsigned int currPtr() const
		{
			return _currPtr;
		}

		inline void wr_reserve(const unsigned int size);
	private:
		unsigned int _currPtr;
		unsigned int _offPtr;
		unsigned int _maxSize;
		
		BufferType _buffer;
};

/*
 *\brief dynamic buffer
 */
typedef ByteBuffer<std::vector<unsigned char> > t_BufferCmdQueue;

/*
 *\brief 模板偏特化
 * 对缓冲的内存重新整理 然后写数据，如果大小不足，重新调整缓存大小
 * 调整规则按照trunkSize的整数倍进行增加
 */
template<>
inline void t_BufferCmdQueue::wr_reserve(const unsigned int size)
{
	if(_maxSize < _currPtr)	
	{
		logger("buffer error");
	}
	if(wr_size() < (size+8))
	{
#define trunkCount(size) (((size) + trunkSize - 1) / trunkSize)
		unsigned int midd = (trunkSize * trunkCount(size+8));
		if(((unsigned int)-1 - _maxSize) <= midd)
		{
			logger("buffer error");
		}
		_maxSize += midd;

		_buffer.resize(_maxSize);
	}
}

/*
 *\brief 静态缓冲区，以栈空间数组的方式分配内存，用于一些临时变量的获取
 */
typedef ByteBuffer<unsigned char [PACKET_ZIP_BUFFER]> t_StackCmdQueue;

template <>
inline void t_StackCmdQueue::wr_reserve(const unsigned int size)
{

}

/*
 *\brief 封装套接口底层函数，提供一个比较通用的接口
 */
class zSocket
{
	public:
		static const int T_RD_MSEC 						= 2100;		 				 //读取超时毫秒数
		static const int T_WR_MSEC						= 5100; 					 //发送超时毫秒数
		
		static const unsigned int PH_LEN				= sizeof(unsigned int);		 //数据包抱头大小
		static const unsigned int PACKET_ZIP_MIN		= 32;						 //数据包压缩最小大小

		static const unsigned int PACKET_ZIP			= 0x40000000;				 //数据包压缩标志
		static const unsigned int INCOMPLETE_READ		= 0x00000001;				 //上次套接口未读取完全标志
		static const unsigned int INCOMPLETE_WRITE		= 0x00000002;				 //上次套接口未写完标志

		static const unsigned int PACKET_MASK			= trunkSize - 1;			 //最大数据包长度掩码
		static const unsigned int MAX_DATABUFFERSIZE	= PACKET_MASK;				 //数据包最大长度,包括包头4字节
		static const unsigned int MAX_DATASIZE			= (MAX_DATABUFFERSIZE-RH_LEN);//数据包最大长度
		static const unsigned int MAX_USERDATASIZE		= (MAX_DATASIZE - 128);		 //用户数据包最大长度

		static const char * getIPByIfName(const char *ifName);

		zSocket(const int sock,const struct sockaddr_in *addr = NULL,const bool compress = false);
		~zSocket();

		int recvToCmd(void *pstrCmd,const int nCmdLen,const bool wait);
		bool sendCmd(const void *pstrCmd,const int nCmdLen,const bool buffer = false);
		bool sendCmdNoPack(const void *pstrCmd,const int nCmdLen,const bool buffer = false);
		bool sync();
		void force_sync();

		int checkIOForRead();
		int checkIOForWrite();
		int recvToBuf_NoPoll();
		int recvToCmd_NoPoll(void *pstrCmd,const int nCmdLen);

		/**
		 *\brief 获取套接口对方的地址
		 *\return IP地址
		 */
		inline const char * getIP() const {  return inet_ntoa(addr.sin_addr); }
		inline const DWORD getAddr() const{  return addr.sin_addr.s_addr; }//htonl(ip) 后的值，结构内部是个union

		/**
		 *\brief 获取套接口对方的port
		 */
		inline const unsigned short getPort() const { return ntohs(addr.sin_port); }
		
		/**
		 *\brief 获取套接口本地地址
		 */
		inline const char *getLocalIP() const { return ntoa(local_addr.sin_addr); }

		/**
		 *\brief 获取套接口本地port
		 */
		inline const unsigned short getLocalPort() const { return ntohs(local_addr.sin_port); }

		/**
		 *\brief 设置读取超时，单位毫秒
		 */
		inline void setReadTimeout(const int msec) { rd_msec = msec; }

		/**
		 *\brief 设置写入超时，单位毫秒
		 */
		inline void setWriteTimeout(const int msec) { wr_msec = msec; }

		/**
		 * \brief 添加检测事件到epoll描述符
		 * \para  kdpfd epoll描述符
		 * \para  events 待添加的事件
		 * \para  ptr 额外参数(用户处理数据使用)
		 */
		inline void addEpoll(int kdpfd,__uint32_t events,void *ptr)
		{
			struct epoll_event ev;
			ev.events = events;
			ev.data.ptr = ptr;
			if(-1 == epoll_ctl(kdpfd,EPOLL_CTL_ADD,sock,&ev))
			{
				char buf[100];
				bzero(buf,sizeof(buf));
				strerror_r(errno,buf,sizeof(buf));
				logger("%s:%s",__FUNCTION__,buf);
			}
		}
		/**
		 * \brief 从epoll描述符删除事件
		 * \para  kdpfd epoll描述符
		 * \para  events 待删除的事件
		 */
		inline void delEpoll(int kdpfd,__uint32_t events)
		{
			struct epoll_event ev;
			ev.events = events;
			ev.data.ptr = NULL;
			if(-1 == epoll_ctl(kdpfd,EPOLL_CTL_DEL,sock,&ev))
			{
				char buf[100];
				bzero(buf,sizeof(buf));
				strerror_r(errno,buf,sizeof(buf));
				logger("%s:%s",__FUNCTION__,buf);
			}
		}

		/**
		 * \brief 填充pollfd结构
		 * \param pfd 待填充的结构
		 * \param events 等待的事件参数
		 */
		inline void fillPollFD(struct pollfd &pfd,short events)
		{
			pfd.fd = sock;
			pfd.events = events;
			pfd.revents = 0;
		}

		//加解密
		inline void setEncMethod(CEncrypt::encMethod m) { enc.setEncMethod(m); }
		inline void set_key_rc5(const unsigned char *data,int nLen,int rounds=RC5_8_ROUNDS) 
		{
			enc.set_key_rc5(data,nLen,rounds);
		}
		inline void set_key_des(const_DES_cblock *key) { enc.set_key_des(key); }
		inline void setEncMask(const unsigned int m) { enc.setEncMask(m); }
		inline void setDecMask(const unsigned int m) { enc.setDecMask(m); }

		inline unsigned int snd_queue_size() { return _snd_queue.rd_size() + _enc_queue.rd_size(); }
		inline unsigned int getBufferSize() const { return _rcv_queue.maxSize() + _snd_queue.maxSize(); }
	private:
		int sock;														//套接口
		struct sockaddr_in addr;										//套接口地址
		struct sockaddr_in local_addr;									//套接口地址
		int rd_msec;													//读取超时，毫秒
		int wr_msec;													//写入超时，毫秒,在内核停留??

		t_BufferCmdQueue _rcv_queue;									//接受缓冲指令队列
		unsigned int _rcv_raw_size;										//接受缓冲解密数据大小
		t_BufferCmdQueue _snd_queue;									//发送缓冲指令队列
		t_BufferCmdQueue _enc_queue;									//加密缓冲指令队列
		unsigned int _current_cmd;
		zMutex mutes;													//线程所

		zTime last_check_time;											//最后一次检测时间

		unsigned int bitmask;											//标记掩码
		CEncrypt enc;													//加密方式

		inline void set_flag(unsigned int _f) { bitmask |= _f; }
		inline bool isset_flag(unsigned int _f) const { return bitmask & _f; }
		inline void clear_flag(unsigned int _f) { bitmask &= ~_f; } 	//清除标志位
		inline void need_enc() const { return CEncrypt::ENCDEC_NONE != enc.getEncMethod(); }

		/**
		 *\brief 返回数据包抱头最小长度
		 */
		inline unsigned int packetMinSize() const { return PH_LEN; }

		/**
		 * \brief 返回整个数据包的长度
		 * \param in 数据包
		 */
		inline unsigned int packetSize(const unsigned char *in) const { return PH_LEN+((*((unsigned int *)in)) & PACKET_MASK); }

		inline int sendRawData(const void *pBuffer,const int nSize);
		inline bool sendRawDataIM(const void *pBuffer,const int nSize);
		inline bool sendRawData_NoPoll(const void *pBuffer,const int nSize);
		inline bool setNonblock();
		inline int waitForRead();
		inline int waitForWrite();
		inline int recvToBuf();

		inline unsigned int packetUnpack(unsigned char *in,const unsigned int nPacketLen,unsigned char *out);
		template <typename buffer_type>
		inline unsigned int packetAppend(unsigned void *pData,const unsigned int nLen,buffer_type &cmd_queue);
		template <typename buffer_type>
		inline unsigned int packetAppendNoEnc(unsigned void *pData,const unsigned int nLen,buffer_type &cmd_queue);
		template <typename buffer_type>
		inline unsigned int packetPackEnc(buffer_type &cmd_queue,const unsigned int current_cmd,const unsigned int offset = 0);
	public:
		template <typename buffer_type>
		static inline unsigned int packetPackZip(const void *pData,const unsigned int nLen,buffer_type &cmd_queue,const bool compress=true);

		///测试变量
		unsigned int debug_currPtr;
		unsigned int debug_offPtr;
		unsigned int debug_max_size;
		unsigned int debug_wait_size;

};

/**
 * \brief 对数据进行组织，需要时压缩，不加密
 * \param pData 代组织的数据，输入
 * \param nLen 待拆包的数据长度
 * \param cmd_queue 输出，存放数据
 * \return 封包后的大小
 */
template <typename buffer_type>
inline unsigned int zSocket::packetAppendNoEnc(const void *pData,const unsigned int nLen,buffer_type &cmd_queue)
{
	return packetPackZip(pData,nLen,cmd_queue,PACKET_ZIP == (bitmask & PACKET_ZIP));
}
template <typename buffer_type>
inline unsigned int zSocket::packetAppend(unsigned void *pData,const unsigned int nLen,buffer_type &cmd_queue)
{
	unsigned int nSize = packetPackZip(pData,nLen,cmd_queue,PACKET_ZIP == (bitmask & PACKET_ZIP));
	if(need_enc())
		nSize = packetPackEnc(cmd_queue,cmd_queue.rd_size());
	return nSize;
}

/**
 * \brief 				对数据进行加密
 * \para cmd_queue  	待加密的数据，输入输出
 * \para current_cmd 	最后一个指令长度
 * \para offset 		待加密数据的偏移
 * \return 				返回加密以后真实数据的大小
 */
template <typename buffer_type>
inline unsigned int zSocket::packetPackEnc(buffer_type &cmd_queue,const unsigned int current_cmd,const unsigned int offset);
{
	unsigned int mod = (cmd_queue.rd_size() - offset) % 8;
	if(0 != mod)
	{
		mod = 8- mod;
		(*(unsigned int *)(&(cmd_queue.rd_buf()[cmd_queue.rd_size() - current_cmd]))) += mod; //??
		cmd_queue.wr_flip(mod);
	}

	//enc
	enc.encdec(&cmd_queue.rd_buf()[offset],cmd_queue.rd_size() - offset,true);

	return cmd_queue.rd_size();
}

/**
 * \brief 			对数据进行压缩，由上层决定是否压缩	
 * \param pData		待压缩的数据，输入
 * \param nLen		待压缩的数据长度，输入
 * \param pBuffer	输出，存放压缩以后的数据
 * \param compress 	当数据包过大时是否压缩
 * \return 			返回加密以后真实数据的大小
 */
template <typename buffer_type>
inline unsigned int zSocket::packetPackZip(const void *pData,const unsigned int nLen,buffer_type &cmd_queue,const bool compress)
{
	unsigned int nSize = nLen > MAX_DATASIZE ? MAX_DATASIZE : nLen;
	unsigned int nMask = 0;
	if(nSize > PACKET_ZIP_MIN && compress) //数据包过大，带压缩标志
	{
		uLong nZipLen = unzip_size(nSize);	
		cmd_queue.wr_reserve(nZipLen + PH_LEN);
		int retcode = compress(&(cmd_queue.wr_buf()[PH_LEN]),&nZipLen,(const Bytef *)pData,nSize);//??
		switch(retcode)
		{
			case Z_OK:
				break;
			case Z_MEM_ERROR:
				logger("error");
				break;
			case Z_BUF_ERROR:
				logger("error");
				break;

		}
		nSize = nZipLen;
		nMask |= PACKET_ZIP
	}
	else
	{
		cmd_queue.wr_reserve(nSize + PH_LEN);
		bcopy(pData,&(cmd_queue.wr_buf()[PH_LEN],nSize));
	}

	(*(unsigned int *)cmd_queue.wr_buf()) = (nSize | nMask);
	cmd_queue.wr_flip(nSize + PH_LEN);

	return nSize + PH_LEN;
}

/**
 *\brief 定义自消息处理接口,所有接收到的TCP数据指令需要通过这个接口处理
 */
class zProcessor
{
	public:
		virtual bool msgParse(const Cmd::t_NullCmd *,const unsigned int) = 0;
}

#endif
